package com.wx.network.handler;

import com.wx.content.DataType;
import com.wx.network.codec.RpcProtocol;
import com.wx.network.context.ServerContextHolder;
import com.wx.network.mesg.Request;
import com.wx.util.SerializationUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;

/**
 * 服务端负责发起本地调用把调用的数据返回给客户端
 */
@Slf4j
public class RpcServerHandler extends SimpleChannelInboundHandler<RpcProtocol> {

    private ApplicationContext applicationContext;
    public RpcServerHandler(ApplicationContext applicationContext){
        this.applicationContext=applicationContext;
    }

    /**
     * 对于客户端发送的数据进行判断
     * 对于不同类型的请求分别进行处理
     * @param channelHandlerContext
     * @param rpcProtocol
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcProtocol rpcProtocol) throws Exception {
        byte[] requestByte = rpcProtocol.getData();
        //使用protocol进行转换，转换为Request类
        Request request = SerializationUtil.unSerialzationObj(requestByte, Request.class);
        RpcHandlerContext context = new RpcHandlerContext();
        //对于请求的类型进行判断
        DataType dataType = request.getDataType();
        int port = ServerContextHolder.getPort();
        switch (dataType){
            case PINFG:
                log.info("服务端收到心跳【{}】",request.getHeatBeatPackage());
                context.setRpcDataOperate(new PingHeartBeatHandler(port));
                break;
            case BUSSINESS:
                context.setRpcDataOperate(new RequestHandler(applicationContext));
                break;
            default:
                break;
        }
        context.operateDate(channelHandlerContext,request);
    }

    /**
     * 发生异常以后关闭连接
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        log.error("{}连接发生异常关闭连接，异常原因{}",ctx.channel().remoteAddress(),cause.getMessage());
    }

    /**
     * 心跳监测，如果四秒管道没有触发读事件就断开连接
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof IdleStateEvent){
            IdleStateEvent event=(IdleStateEvent)evt;
            switch (event.state()){
                case READER_IDLE:
                    //断开连接
                    ctx.close();
                    log.info("服务器没有收到【{}】的心跳主动断开连接",ctx.channel().remoteAddress());
                    break;
                default:
                    break;
            }
        }
        super.userEventTriggered(ctx, evt);
    }

    /**
     * 通道断开
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        log.info("【{}】连接已断开",ctx.channel().remoteAddress());
    }

}
